Skip to content

Conversation

ojhunt
Copy link
Contributor

@ojhunt ojhunt commented Jun 7, 2025

This hardens the unwinding logic and datastructures on systems
that support pointer authentication.

The approach taken to hardening is to harden the schemas of as many
high value fields in the myriad structs as possible, and then also
explicitly qualify local variables referencing privileged or security
critical values.

This does introduce ABI linkage between libcxx, libcxxabi, and
libunwind but those are in principle separate from the OS itself
so we've kept the schema definitions in the library specific headers
rather than ptrauth.h

@ojhunt ojhunt requested review from asl, ahmedbougacha and ldionne June 7, 2025 02:10
@ojhunt ojhunt requested review from a team as code owners June 7, 2025 02:10
@ojhunt ojhunt added compiler-rt libc++abi libc++abi C++ Runtime Library. Not libc++. libunwind hardening Issues related to the hardening effort labels Jun 7, 2025
@llvmbot llvmbot added compiler-rt:builtins PGO Profile Guided Optimizations labels Jun 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 7, 2025

@llvm/pr-subscribers-pgo
@llvm/pr-subscribers-libcxxabi

@llvm/pr-subscribers-libunwind

Author: Oliver Hunt (ojhunt)

Changes

This hardens the unwinding logic and datastructures on systems that support pointer authentication.

The approach taken to hardening is to harden the schemas of as many high value fields in the myriad structs as possible, and then also explicitly qualify local variables referencing privileged or security critical values.

This ABI is exposed to the personality functions, and so updating to conform to that is a mandatory change, but to reduce the risk of oracles, the adoption also hardened the locals and datastructures in compiler-rt and libcxxabi.

We're gating these on defined(__APPLE__) so other platforms are able to qualify before enabling. An alternative would be an feature flag that could be used instead but I didn't want to force such a change if it was not considered
necessary.


Patch is 51.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/143230.diff

14 Files Affected:

  • (modified) compiler-rt/lib/builtins/gcc_personality_v0.c (+63-6)
  • (modified) compiler-rt/lib/profile/InstrProfilingValue.c (+7-1)
  • (modified) libcxxabi/include/__cxxabi_config.h (+47-1)
  • (modified) libcxxabi/src/cxa_exception.h (+16-14)
  • (modified) libcxxabi/src/cxa_personality.cpp (+61-8)
  • (modified) libunwind/include/libunwind.h (+70-8)
  • (modified) libunwind/src/AddressSpace.hpp (+30-14)
  • (modified) libunwind/src/DwarfInstructions.hpp (+8-3)
  • (modified) libunwind/src/DwarfParser.hpp (+40-4)
  • (modified) libunwind/src/Registers.hpp (+109-4)
  • (modified) libunwind/src/UnwindCursor.hpp (+55-17)
  • (modified) libunwind/src/UnwindLevel1.c (+30-6)
  • (modified) libunwind/src/UnwindRegistersSave.S (+10)
  • (modified) libunwind/src/libunwind.cpp (+34)
diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index ef63a5fb83472..42b992949d2cc 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,6 +30,45 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)             \
+    __ptrauth_restricted_intptr(key, addressDiscriminated,                     \
+                            ptrauth_string_discriminator(discriminatorString))
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)             \
+    __ptrauth(key, addressDiscriminated,                                       \
+              ptrauth_string_discriminator(discriminatorString))
+#endif
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * PDC : ptrauth_key_process_dependent_code
+//  * RA  : ptrauth_key_return_address
+//  * FN  : ptrauth_key_function_pointer
+#define PERSONALITY_PTRAUTH_RI_FN(__discriminator)                             \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_function_pointer,        \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_PDC(__discriminator)                            \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_code,  \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_RA(__discriminator)                             \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_return_address,          \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+
 // Pointer encodings documented at:
 //   http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
 
@@ -205,7 +244,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
     return continueUnwind(exceptionObject, context);
 
   uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
-  uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
+  uintptr_t PERSONALITY_PTRAUTH_RI_FN("__gcc_personality_v0'funcStart")
+      funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
   uintptr_t pcOffset = pc - funcStart;
 
   // Parse LSDA header.
@@ -224,11 +264,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
   const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
   const uint8_t *p = callSiteTableStart;
   while (p < callSiteTableEnd) {
-    uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
-    size_t length = readEncodedPointer(&p, callSiteEncoding);
-    size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+    uintptr_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'start")
+        start = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'length")
+        length = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'landingPadOffset")
+        landingPadOffset = readEncodedPointer(&p, callSiteEncoding);
     readULEB128(&p); // action value not used for C code
-    if (landingPad == 0)
+    if (landingPadOffset == 0)
       continue; // no landing pad for this entry
     if ((start <= pcOffset) && (pcOffset < (start + length))) {
       // Found landing pad for the PC.
@@ -238,7 +281,21 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
                     (uintptr_t)exceptionObject);
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
-      _Unwind_SetIP(context, (funcStart + landingPad));
+#define LANDING_PAD_DISCRIMINATOR "__gcc_personality_v0'landingPad"
+      size_t PERSONALITY_PTRAUTH_RI_RA(LANDING_PAD_DISCRIMINATOR)
+          landingPad = funcStart + landingPadOffset;
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+      uintptr_t stack_pointer = _Unwind_GetGR(context, -2);
+      const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
+          &landingPad,
+          ptrauth_string_discriminator(LANDING_PAD_DISCRIMINATOR));
+      uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
+          *(void **)&landingPad, ptrauth_key_function_pointer,
+          existingDiscriminator, ptrauth_key_return_address, stack_pointer);
+      _Unwind_SetIP(context, newIP);
+#else
+      _Unwind_SetIP(context, landingPad);
+#endif
       return _URC_INSTALL_CONTEXT;
     }
   }
diff --git a/compiler-rt/lib/profile/InstrProfilingValue.c b/compiler-rt/lib/profile/InstrProfilingValue.c
index a608d41d39e77..cd6ae3d7a4248 100644
--- a/compiler-rt/lib/profile/InstrProfilingValue.c
+++ b/compiler-rt/lib/profile/InstrProfilingValue.c
@@ -83,7 +83,13 @@ __llvm_profile_iterate_data(const __llvm_profile_data *Data) {
 /* This method is only used in value profiler mock testing.  */
 COMPILER_RT_VISIBILITY void *
 __llvm_get_function_addr(const __llvm_profile_data *Data) {
-  return Data->FunctionPointer;
+  void *FP = Data->FunctionPointer;
+#if __has_feature(ptrauth_calls)
+  // This is only used for tests where we compare against what happens to be
+  // signed pointers.
+  FP = ptrauth_sign_unauthenticated(FP, VALID_CODE_KEY, 0);
+#endif
+   return FP;
 }
 
 /* Allocate an array that holds the pointers to the linked lists of
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 759445dac91f9..e67d065fe57f3 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -32,7 +32,8 @@
 #endif
 
 #if defined(_WIN32)
- #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
+ #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) ||                     \
+     (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
   #define _LIBCXXABI_HIDDEN
   #define _LIBCXXABI_DATA_VIS
   #define _LIBCXXABI_FUNC_VIS
@@ -109,4 +110,49 @@
 #  define _LIBCXXABI_NOEXCEPT noexcept
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)  \
+    __ptrauth(__key,__address_discriminated,                                   \
+              ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// during the ptrauth upstreaming process.
+#  if __has_feature(ptrauth_restricted_intptr_qualifier)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)                \
+    __ptrauth_restricted_intptr(__key,__address_discriminated,                 \
+                                ptrauth_string_discriminator(__discriminator))
+#  else
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)                \
+    __ptrauth(__key,__address_discriminated,                                   \
+              ptrauth_string_discriminator(__discriminator))
+#  endif
+#else
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * _RI : qualifier is __ptrauth_restricted_intptr
+//  * PDD : key is ptrauth_key_process_dependent_data
+//  * FN  : key is ptrauth_key_function_pointer
+#define _LIBCXXABI_PTRAUTH_PDD(__discriminator)                                \
+    _LIBCXXABI_PTRAUTH(ptrauth_key_process_dependent_data,                     \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_FN(__discriminator)                                 \
+    _LIBCXXABI_PTRAUTH(ptrauth_key_function_pointer,                           \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_RI_PDD(__discriminator)                             \
+    _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_data,   \
+                                         /*__address_discriminated=*/1,        \
+                                         __discriminator)
+
 #endif // ____CXXABI_CONFIG_H
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index aba08f2992103..4c69d48048f02 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,10 +47,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* _LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") exceptionDestructor)(void*);
 #endif
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler  terminateHandler;
+    std::unexpected_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void *catchTemp;
-    void *adjustedPtr;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,6 +79,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
 // The layout of this structure MUST match the layout of __cxa_exception, with
 // primaryException instead of referenceCount.
+// The tags used in the pointer authentication qualifiers also need to match
+// those of the corresponding members in __cxa_exception.
 struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
     void* reserve; // padding.
@@ -86,9 +88,9 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler terminateHandler;
+    void(_LIBCXXABI_DTOR_FUNC* _LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") exceptionDestructor)(void*);
+    std::unexpected_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -99,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void * catchTemp;
-    void *adjustedPtr;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 5f6e75c5be19c..cbb3f46e0f55c 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -22,6 +22,12 @@
 #include "private_typeinfo.h"
 #include "unwind.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#include "libunwind.h"
+
 // TODO: This is a temporary workaround for libc++abi to recognize that it's being
 // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
 // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove
@@ -527,12 +533,19 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
+#define _LIBCXXABI_PTRAUTH_KEY ptrauth_key_process_dependent_code
+typedef const uint8_t* _LIBCXXABI_PTRAUTH_PDD("scan_results::languageSpecificData") lsd_ptr_t;
+typedef const uint8_t* _LIBCXXABI_PTRAUTH_PDD("scan_results::actionRecord") action_ptr_t;
+#define _LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC "scan_results::landingPad"
+typedef uintptr_t _LIBCXXABI_PTRAUTH_RI_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) landing_pad_t;
+typedef void* _LIBCXXABI_PTRAUTH_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) landing_pad_ptr_t;
+
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    const uint8_t* actionRecord;         // Currently unused.  Retained to ease future maintenance.
-    const uint8_t* languageSpecificData;  // Needed only for __cxa_call_unexpected
-    uintptr_t      landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -541,7 +554,33 @@ struct scan_results
 };
 
 }  // unnamed namespace
+}
 
+namespace {
+// The logical model for casting authenticated function pointers makes
+// it impossible to directly cast them without breaking the authentication,
+// as a result we need this pair of helpers.
+template <typename PtrType>
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+  union {
+    landing_pad_t* as_landing_pad;
+    landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  *u.as_pointer = out;
+}
+
+static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
+  union {
+    const landing_pad_t* as_landing_pad;
+    const landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  return *u.as_pointer;
+}
+} // unnamed namespace
+
+extern "C" {
 static
 void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -557,7 +596,22 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+  auto stack_pointer = _Unwind_GetGR(context, UNW_REG_SP);
+  // We manually re-sign the IP as the __ptrauth qualifiers cannot
+  // express the required relationship with the destination address
+  const auto existingDiscriminator = ptrauth_blend_discriminator(
+      &results.landingPad,
+      ptrauth_string_discriminator(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC));
+  unw_word_t newIP = (unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
+                                                         _LIBCXXABI_PTRAUTH_KEY,
+                                                         existingDiscriminator,
+                                                         ptrauth_key_return_address,
+                                                         stack_pointer);
+  _Unwind_SetIP(context, newIP);
+#else
   _Unwind_SetIP(context, results.landingPad);
+#endif
 }
 
 /*
@@ -691,12 +745,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
-        uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
+        landing_pad_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
 #else  // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
         // ip is 1-based index into this table
-        uintptr_t landingPad = readULEB128(&callSitePtr);
+        landing_pad_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
 #endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
@@ -935,8 +989,7 @@ __gxx_personality_v0
         results.ttypeIndex = exception_header->handlerSwitchValue;
         results.actionRecord = exception_header->actionRecord;
         results.languageSpecificData = exception_header->languageSpecificData;
-        results.landingPad =
-            reinterpret_cast<uintptr_t>(exception_header->catchTemp);
+        set_landing_pad_as_ptr(results, exception_header->catchTemp);
         results.adjustedPtr = exception_header->adjustedPtr;
 
         // Jump to the handler.
@@ -970,7 +1023,7 @@ __gxx_personality_v0
             exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
             exc->actionRecord = results.actionRecord;
             exc->languageSpecificData = results.languageSpecificData;
-            exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
+            exc->catchTemp = get_landing_pad_as_ptr(results);
             exc->adjustedPtr = results.adjustedPtr;
 #ifdef __WASM_EXCEPTIONS__
             // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index b2dae8feed9a3..e7375bbca1b3d 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,6 +43,61 @@
   #define LIBUNWIND_AVAIL
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#define _LIBUNWIND_PTRAUTH(__key, __address_discriminated, __discriminator)    \
+  __ptrauth(__key, __address_discriminated,                                    \
+            ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// developed during the ptrauth upstreaming process.
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated,   \
+                                             __discriminator)                  \
+  __ptrauth_restricted_intptr(__key, __address_discriminated,                  \
+             ptrauth_string_discriminator(__discriminator...
[truncated]

Copy link

github-actions bot commented Jun 7, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions h,c,hpp,cpp -- compiler-rt/lib/builtins/gcc_personality_v0.c libcxxabi/include/__cxxabi_config.h libcxxabi/src/cxa_exception.cpp libcxxabi/src/cxa_exception.h libcxxabi/src/cxa_personality.cpp libunwind/include/__libunwind_config.h libunwind/include/libunwind.h libunwind/src/AddressSpace.hpp libunwind/src/CompactUnwinder.hpp libunwind/src/DwarfInstructions.hpp libunwind/src/DwarfParser.hpp libunwind/src/Registers.hpp libunwind/src/UnwindCursor.hpp libunwind/src/UnwindLevel1.c libunwind/src/libunwind.cpp

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index 2eb77d861..aa8969e59 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,7 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
-    void *__ptrauth_cxxabi_catch_temp catchTemp;
-    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -88,7 +88,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
@@ -102,10 +102,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #else
     int handlerSwitchValue;
 
-    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
-    void *__ptrauth_cxxabi_catch_temp catchTemp;
-    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 14e6f4b07..16b424901 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -564,10 +564,10 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
-typedef const uint8_t *__ptrauth_scan_results_lsd lsd_ptr_t;
-typedef const uint8_t *__ptrauth_scan_results_action_record action_ptr_t;
+typedef const uint8_t* __ptrauth_scan_results_lsd lsd_ptr_t;
+typedef const uint8_t* __ptrauth_scan_results_action_record action_ptr_t;
 typedef uintptr_t __ptrauth_scan_results_landingpad_intptr landing_pad_t;
-typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t;
+typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
 
 struct scan_results
 {
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 1e5232392..9122243ac 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -73,11 +73,12 @@
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
 # elif defined(__aarch64__)
 #  define _LIBUNWIND_TARGET_AARCH64 1
-#  if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
-#    define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
-#  elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
-#    #error "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
-#  endif
+#if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
+#define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
+#elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
+# #error                                                                       \
+    "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
+#endif
 #define _LIBUNWIND_CONTEXT_SIZE 67
 #  if defined(__SEH__)
 #    define _LIBUNWIND_CURSOR_SIZE 164
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 5d5b583bb..c44bf3435 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -45,100 +45,115 @@
 
 #if __has_feature(ptrauth_calls)
 
-  #include <ptrauth.h>
+#include <ptrauth.h>
 
-  #if __has_extension(ptrauth_restricted_intptr_qualifier)
-    #define __unwind_ptrauth_restricted_intptr(...) \
-      __ptrauth_restricted_intptr(__VA_ARGS__)
-  #else
-    #define __unwind_ptrauth_restricted_intptr(...) \
-      __ptrauth(__VA_ARGS__)
-  #endif
+#if __has_extension(ptrauth_restricted_intptr_qualifier)
+#define __unwind_ptrauth_restricted_intptr(...)                                \
+  __ptrauth_restricted_intptr(__VA_ARGS__)
+#else
+#define __unwind_ptrauth_restricted_intptr(...) __ptrauth(__VA_ARGS__)
+#endif
 
 // ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
-  #define __ptrauth_unwind_upi_handler_disc 0x7405
+#define __ptrauth_unwind_upi_handler_disc 0x7405
 
-  #define __ptrauth_unwind_upi_handler \
-    __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
+#define __ptrauth_unwind_upi_handler                                           \
+  __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
 
-  #define __ptrauth_unwind_upi_handler_intptr \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\
-                                       __ptrauth_unwind_upi_handler_disc)
+#define __ptrauth_unwind_upi_handler_intptr                                    \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,          \
+                                     __ptrauth_unwind_upi_handler_disc)
 
 // ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
-  #define __ptrauth_unwind_upi_startip \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
+#define __ptrauth_unwind_upi_startip                                           \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1,  \
+                                     0xCA2C)
 
 // ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
-  #define __ptrauth_unwind_upi_endip \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
+#define __ptrauth_unwind_upi_endip                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1,  \
+                                     0xE183)
 
 // ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
-  #define __ptrauth_unwind_upi_lsda \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
+#define __ptrauth_unwind_upi_lsda                                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x83DE)
 
 // ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
-  #define __ptrauth_unwind_upi_flags \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
+#define __ptrauth_unwind_upi_flags                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x79A1)
 
 // ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
-  #define __ptrauth_unwind_upi_info \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
+#define __ptrauth_unwind_upi_info                                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0xC20C)
 
 // ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
-  #define __ptrauth_unwind_upi_extra \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
+#define __ptrauth_unwind_upi_extra                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x03DF)
 
 // ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
-  #define __ptrauth_unwind_registers_arm64_link_reg \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
+#define __ptrauth_unwind_registers_arm64_link_reg                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1,    \
+                                     0x8301)
 
 // ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
-  #define __ptrauth_unwind_uis_dso_base \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
+#define __ptrauth_unwind_uis_dso_base                                          \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x4FF5)
 
 // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
-  #define __ptrauth_unwind_uis_dwarf_section \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
+#define __ptrauth_unwind_uis_dwarf_section                                     \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x4974)
 
-// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
-  #define __ptrauth_unwind_uis_dwarf_section_length \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
+// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") ==
+// 0x2A9A
+#define __ptrauth_unwind_uis_dwarf_section_length                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x2A9A)
 
-// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
-  #define __ptrauth_unwind_uis_compact_unwind_section \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") ==
+// 0xA27B
+#define __ptrauth_unwind_uis_compact_unwind_section                            \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0xA27B)
 
-// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
-  #define __ptrauth_unwind_uis_compact_unwind_section_length \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length")
+// == 0x5D0A
+#define __ptrauth_unwind_uis_compact_unwind_section_length                     \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x5D0A)
 
 // ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
-  #define __ptrauth_unwind_cie_info_personality_disc 0x6A40
-  #define __ptrauth_unwind_cie_info_personality \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
-                                       __ptrauth_unwind_cie_info_personality_disc)
+#define __ptrauth_unwind_cie_info_personality_disc 0x6A40
+#define __ptrauth_unwind_cie_info_personality                                  \
+  __unwind_ptrauth_restricted_intptr(                                          \
+      ptrauth_key_function_pointer, 1,                                         \
+      __ptrauth_unwind_cie_info_personality_disc)
 
 // ptrauth_string_discriminator("personality") == 0x7EAD)
-  #define __ptrauth_unwind_pacret_personality_disc 0x7EAD
+#define __ptrauth_unwind_pacret_personality_disc 0x7EAD
 
 #else
 
-  #define __ptrauth_unwind_upi_handler
-  #define __ptrauth_unwind_upi_handler_intptr
-  #define __ptrauth_unwind_upi_startip
-  #define __ptrauth_unwind_upi_endip
-  #define __ptrauth_unwind_upi_lsda
-  #define __ptrauth_unwind_upi_flags
-  #define __ptrauth_unwind_upi_info
-  #define __ptrauth_unwind_upi_extra
-  #define __ptrauth_unwind_registers_arm64_link_reg
-  #define __ptrauth_unwind_uis_dso_base
-  #define __ptrauth_unwind_uis_dwarf_section
-  #define __ptrauth_unwind_uis_dwarf_section_length
-  #define __ptrauth_unwind_uis_compact_unwind_section
-  #define __ptrauth_unwind_uis_compact_unwind_section_length
-  #define __ptrauth_unwind_cie_info_personality
+#define __ptrauth_unwind_upi_handler
+#define __ptrauth_unwind_upi_handler_intptr
+#define __ptrauth_unwind_upi_startip
+#define __ptrauth_unwind_upi_endip
+#define __ptrauth_unwind_upi_lsda
+#define __ptrauth_unwind_upi_flags
+#define __ptrauth_unwind_upi_info
+#define __ptrauth_unwind_upi_extra
+#define __ptrauth_unwind_registers_arm64_link_reg
+#define __ptrauth_unwind_uis_dso_base
+#define __ptrauth_unwind_uis_dwarf_section
+#define __ptrauth_unwind_uis_dwarf_section_length
+#define __ptrauth_unwind_uis_compact_unwind_section
+#define __ptrauth_unwind_uis_compact_unwind_section_length
+#define __ptrauth_unwind_cie_info_personality
 #endif
 
 #if defined(_WIN32) && defined(__SEH__)
@@ -186,18 +201,23 @@ typedef double unw_fpreg_t;
 #endif
 
 struct unw_proc_info_t {
-  unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */
-  unw_word_t __ptrauth_unwind_upi_endip end_ip;     /* address after end of function */
-  unw_word_t __ptrauth_unwind_upi_lsda lsda;        /* address of language specific data area, */
-                                                    /* or zero if not used */
+  unw_word_t __ptrauth_unwind_upi_startip
+      start_ip; /* start address of function */
+  unw_word_t __ptrauth_unwind_upi_endip
+      end_ip; /* address after end of function */
+  unw_word_t __ptrauth_unwind_upi_lsda
+      lsda; /* address of language specific data area, */
+            /* or zero if not used */
 
   unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
-  unw_word_t  gp;                                   /* not used */
-  unw_word_t __ptrauth_unwind_upi_flags flags;      /* not used */
-  uint32_t    format;                               /* compact unwind encoding, or zero if none */
-  uint32_t    unwind_info_size;                     /* size of DWARF unwind info, or zero if none */
-  unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
-  unw_word_t __ptrauth_unwind_upi_extra extra;      /* mach_header of mach-o image containing func */
+  unw_word_t gp;                               /* not used */
+  unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */
+  uint32_t format;           /* compact unwind encoding, or zero if none */
+  uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
+  unw_word_t __ptrauth_unwind_upi_info
+      unwind_info; /* address of DWARF unwind info, or zero */
+  unw_word_t __ptrauth_unwind_upi_extra
+      extra; /* mach_header of mach-o image containing func */
 };
 typedef struct unw_proc_info_t unw_proc_info_t;
 
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 63f9cb367..f38dda47c 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -129,27 +129,24 @@ struct UnwindInfoSections {
     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   // No dso_base for SEH.
-  uintptr_t __ptrauth_unwind_uis_dso_base
-                  dso_base = 0;
+  uintptr_t __ptrauth_unwind_uis_dso_base dso_base = 0;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   size_t          text_segment_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-  uintptr_t __ptrauth_unwind_uis_dwarf_section
-                  dwarf_section = 0;
-  size_t __ptrauth_unwind_uis_dwarf_section_length
-                  dwarf_section_length = 0;
+  uintptr_t __ptrauth_unwind_uis_dwarf_section dwarf_section = 0;
+  size_t __ptrauth_unwind_uis_dwarf_section_length dwarf_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
   uintptr_t       dwarf_index_section;
   size_t          dwarf_index_section_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  uintptr_t __ptrauth_unwind_uis_compact_unwind_section
-                  compact_unwind_section = 0;
+  uintptr_t __ptrauth_unwind_uis_compact_unwind_section compact_unwind_section =
+      0;
   size_t __ptrauth_unwind_uis_compact_unwind_section_length
-                  compact_unwind_section_length = 0;
+      compact_unwind_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
   uintptr_t       arm_section;
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index d9fa76c57..d2822e8be 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -302,7 +302,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64) && \
+#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      \
     !defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
       // There are two ways of return address signing: pac-ret (enabled via
       // -mbranch-protection=pac-ret) and ptrauth-returns (enabled as part of
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index cca3ae0cc..56b4b35b3 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -325,7 +325,7 @@ template <typename CIE_Info, typename T>
   memmove((void *)&info->personality, (void *)&signed_personality,
           sizeof(signed_personality));
 }
-}
+} // namespace
 
 /// Extract info from a CIE
 template <typename A>
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index adbab6687..4ed1db540 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1863,29 +1863,25 @@ public:
 
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
-  uint64_t  getIP() const {
+  uint64_t getIP() const {
     uint64_t value = _registers.__pc;
 #if __has_feature(ptrauth_calls)
     // Note the value of the PC was signed to its address in the register state
     // but everyone else expects it to be sign by the SP, so convert on return.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              getSP());
+    value = (uint64_t)ptrauth_auth_and_resign(
+        (void *)_registers.__pc, ptrauth_key_return_address, &_registers.__pc,
+        ptrauth_key_return_address, getSP());
 #endif
     return value;
   }
-  void      setIP(uint64_t value) {
+  void setIP(uint64_t value) {
 #if __has_feature(ptrauth_calls)
     // Note the value which was set should have been signed with the SP.
     // We then resign with the slot we are being stored in to so that both SP
     // and LR can't be spoofed at the same time.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)value,
-                                              ptrauth_key_return_address,
-                                              getSP(),
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc);
+    value = (uint64_t)ptrauth_auth_and_resign(
+        (void *)value, ptrauth_key_return_address, getSP(),
+        ptrauth_key_return_address, &_registers.__pc);
 #endif
     _registers.__pc = value;
   }
@@ -1898,10 +1894,9 @@ public:
                                   link_reg_t *referenceAuthedLinkRegister) {
     // If we are in an arm64/arm64e frame, then the PC should have been signed
     // with the SP
-    *referenceAuthedLinkRegister =
-      (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister,
-                                  ptrauth_key_return_address,
-                                  _registers.__sp);
+    *referenceAuthedLinkRegister = (uint64_t)ptrauth_auth_data(
+        (void *)inplaceAuthedLinkRegister, ptrauth_key_return_address,
+        _registers.__sp);
   }
 #endif
 

@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch 2 times, most recently from 6810396 to 637245f Compare June 7, 2025 02:22
@asl
Copy link
Collaborator

asl commented Jun 7, 2025

@kovdan01 @atrosinenko Please take a look

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 7, 2025

Updating formatting before review - had discussed with Louis and he expressed a preference for some of it, but this llvm.org style bot complains many other cases (likely a local config issue when I was trying to cleanup the downstream code.

So I've updated with a direct clang-format fix.

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 8, 2025

unused variable errors are likely fallout from refactoring and workaround removals I did as part of the prep, will do some cleanup/diagnostics work later this week.

I mostly wanted to get this available to others to see whether they were ok adopting this rather than rolling their own version.

@kovdan01
Copy link
Contributor

@ojhunt JFYI: I've published a couple of small fixes I've applied locally at https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/. Maybe this would be useful

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 18, 2025

@ojhunt JFYI: I've published a couple of small fixes I've applied locally at https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/. Maybe this would be useful

I'd posted this to try and avoid too much duplicated work so it's highly possible some of these issues are due to me screwing up refactoring, cleanups, or the patch preparation. I'll get back to this after wg21 wraps up this week, so sorry for the delays.

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 25, 2025

I'll be back to working on this later today - there's a pile of feedback, and a bunch of nonsense that I managed to accidentally accrue and/or re-format when pushing the PR so it will take a little time to unbreak that. It may be easiest to force push a repaired PR first and then address comments.

I also realize that some of the breakage might be due to mismatched APPLE vs has_feature(actual_feature)

Copy link
Contributor

@atrosinenko atrosinenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested this patch on Linux with aarch64-linux-pauthtest triple and custom-built sysroot, here are the results.

In my setup, the tests pass on the following modified branch: https://github.com/atrosinenko/llvm-project/commits/pointer-authenticated-unwinding-fix1/. It is based on https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/ with the following changes:

  • Currently, several parts of the patch are only enabled on Apple targets. For testing purposes, I unconditionally enabled parts of this patch guarded by defined(__APPLE__).
  • It turned out that __has_feature(ptrauth_qualifier) does not work in mainline, so I replaced it with __has_feature(ptrauth_intrinsics). I expect the correct solution proposed by @kovdan01 (replacing with __has_extension(ptrauth_qualifier)) to behave identically.
  • The change to compiler-rt/lib/profile/InstrProfilingValue.c seems to be unrelated to libunwind
  • The most meaningful change is updating signing schemas is several places - see inline comments. Additionally, I had to update a few other places that I cannot add inline comments to
    • in Registers_arm64::getRegister and Registers_arm64::setRegister, replace direct references to _registers.__pc with calls to getIP() and setIP(), correspondingly
    • disable the existing pauth-related logic in DwarfInstructions<A, R>::stepWithDwarf

The fact I'm worried about is whether implicit signing and authentication on accesses to __ptrauth-qualified fields may introduce signing or authentication oracles usable by an attacker, since many values stored to these fields are initially non-signed. This is possibly mitigated by the fact that all these fields use address diversity with distinct integer discriminators and/or the original values are taken from read-only memory. On the other hand, discriminator computation, auth / sign intrinsic and load / store to memory are currently three separate operations when accessing a __ptrauth-qualified field, thus spilling of intermediate values to the stack is possible. Furthermore, even if the non-signed value originates from a read-only memory, this is not expressed in LLVM IR terms, thus the optimization pipeline may transform sensitive instruction sequences in an unsafe way.

@kovdan01
Copy link
Contributor

kovdan01 commented Sep 22, 2025

@ojhunt I closed all the threads which are no longer relevant or are duplicates. Now we have only 5 non-trivial and 5 trivial issues which really need to be resolved before merging the PR. All other enhancements could be done as follow-up patches.

I've created pointer-authenticated-unwinding-2025-09-22-with-fixes in my fork containing fixes for all the non-trivial issues listed below. Commit links are provided in the list below and in corresponding threads.

Please let me know if you have any questions or any help is needed regarding this.

To be done in scope of this PR

Trivial formatting issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

  1. https://github.com/llvm/llvm-project/pull/143230/files#r2369166326
  2. https://github.com/llvm/llvm-project/pull/143230/files#r2369411804
  3. https://github.com/llvm/llvm-project/pull/143230/files#r2369413223
  4. https://github.com/llvm/llvm-project/pull/143230/files#r2369645403
  5. https://github.com/llvm/llvm-project/pull/143230/files#r2369644193

Non-trivial styling-related issues

  1. Refactor preprocessor checks against ptrauth. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369029642 and commit 644405b
  2. Avoid use of __ptrauth_restricted_intptr which is not present in mainline. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369036612 and commit a2390e1. I do get the point that it's needed in downstream, but I suppose that it's better to avoid exposing downstream-specific stuff to mainline. I suppose that you can use a simple downstream patch over mainline libunwind which would resolve the build issue for you.
  3. Do smth with [[maybe_unused]] attribute which only serves as a workaround for a spurious compiler bug. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2368805350 and commit 4eaa8c7

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Other non-trivial issues

Verify FP is handled correctly https://github.com/llvm/llvm-project/pull/143230/files#r2369428305

To be done as a follow-up

  1. [PAC] Update pointer authentication docs #96528 (comment)
  2. [PAC][libunwind] Refactor way of describing internal signing schemas #160101
  3. [PAC][libunwind] Unify signed return address handling logic #160110
  4. [PAC][libunwind] Investigate if compatibility with v8.2-a could be enhanced #160114
  5. [PAC][libunwind] Enhance comments and error messages related to libunwind hardening #160117
  6. [PAC][libunwind] Move signing schemas which are part of public ABI to ptrauth.h header #160119
  7. [PAC][ibunwind] Support signed personality pointer on Linux targets #160120

@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch from 1e5b4cb to 5f5f75e Compare September 27, 2025 23:50
This hardens the unwinding logic and datastructures on systems
that support pointer authentication.
The approach taken to hardening is to harden the schemas of as many
high value fields in the myriad structs as possible, and then also
explicitly qualify local variables referencing privileged or security
critical values.
This does introduce ABI linkage between libcxx, libcxxabi, and
libunwind but those are in principle separate from the OS itself
so we've kept the schema definitions in the library specific headers
rather than ptrauth.h
At some point I lost the changes to loadAndAuthenticateLinkRegister
I also updated schema names in libunwind to be more consistent
Finally while looking at the total diff I saw some places that
the formatting could be improved.
@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch from 5f5f75e to ad625da Compare September 27, 2025 23:50
@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 27, 2025

Had to rebase as there was a divergence between my tree and this one - possibly I accidentally merged main to the PR

@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 28, 2025

@ojhunt I closed all the threads which are no longer relevant or are duplicates.

👍

To be done in scope of this PR

Trivial formatting issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

Done

Non-trivial styling-related issues

  1. Refactor preprocessor checks against ptrauth. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369029642 and commit 644405b
  2. Avoid use of __ptrauth_restricted_intptr which is not present in mainline. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369036612 and commit a2390e1. I do get the point that it's needed in downstream, but I suppose that it's better to avoid exposing downstream-specific stuff to mainline. I suppose that you can use a simple downstream patch over mainline libunwind which would resolve the build issue for you.

That would mean that apple clang will not be able to build the runtimes. That's not a real option.

  1. Do smth with [[maybe_unused]] attribute which only serves as a workaround for a spurious compiler bug. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2368805350 and commit 4eaa8c7

I've moved this behind a matching #define of the code that calls them, I'm trying to work out if there is a real reason for the functions being separated from their usage as much as they are.

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

Other non-trivial issues

Verify FP is handled correctly https://github.com/llvm/llvm-project/pull/143230/files#r2369428305

It is, I've fixed the misleading - we were experimenting with signed frame pointers for a while.

To be done as a follow-up

  1. [PAC] Update pointer authentication docs #96528 (comment)
  2. [PAC][libunwind] Refactor way of describing internal signing schemas #160101
  3. [PAC][libunwind] Unify signed return address handling logic #160110
  4. [PAC][libunwind] Investigate if compatibility with v8.2-a could be enhanced #160114

Pinged Ahmed on this one, I don't know the full impact of that change

  1. [PAC][libunwind] Enhance comments and error messages related to libunwind hardening #160117

My preference would be to remove those from release builds entirely and replace LIBUNWIND_ABORT() with explicit immediate traps.

  1. [PAC][libunwind] Move signing schemas which are part of public ABI to ptrauth.h header #160119

This is possibly difficult. The functional ABI implication of most of these is purely between libcxx and libcxxabi, and our platform model does not support updating/changing those separately, which means we think we might be able to change/improve some of the aspects in future. Moving them to ptrauth.h functionally removes that option even if there was no technical reason to.

  1. [PAC][ibunwind] Support signed personality pointer on Linux targets #160120

this is the "personality" discriminated one right? I think I already incorporated it into the latest revision.

@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 28, 2025

Sigh, built wrong repo, basic errors which I'm fixing now

T signed_personality) {
static_assert(sizeof(info->personality) == sizeof(signed_personality),
"Signed personality is the wrong size");
memmove((void *)&info->personality, (void *)&signed_personality,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I guess we can just use memcpy since memmove has additional overhead of handling overlapping memory regions. Here, signed_personality is a local variable, so we can guarantee that there is no overlapping.

Also, it's probably worth explicitly including <string.h> (well, <cstring> should be better for C++ headers, but we already have includes for C-style headers, so let's stick with existing conventions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, other platforms haven't simply adopted the "handle overlap correctly everywhere" approach? :-/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, other platforms haven't simply adopted the "handle overlap correctly everywhere" approach? :-/

@ojhunt I honestly can't say for all the platforms, but I suppose that memcpy expresses the intention better than memmove here

@kovdan01
Copy link
Contributor

@ojhunt Thanks for an update! I've resolved several threads, but some things should still be fixed.

Please let me know if you have any comments/questions or any help is needed from my side.

Trivial style-related issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

  1. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  2. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  3. [runtimes][PAC] Harden unwinding when possible #143230 (comment)

Non-trivial styling-related issues

Refactor preprocessor checks against ptrauth. See thread #143230 (comment) and proposed fix 644405b

Breaking change to be reverted

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

This does not seem to fix the originally described issue, moreover, it looks like this breaks previously working behavior. See #143230 (comment).

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 2, 2025

@ojhunt Thanks for an update! I've resolved several threads, but some things should still be fixed.

Please let me know if you have any comments/questions or any help is needed from my side.

Trivial style-related issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

  1. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  2. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  3. [runtimes][PAC] Harden unwinding when possible #143230 (comment)

I think fixed?

Non-trivial styling-related issues

Refactor preprocessor checks against ptrauth. See thread #143230 (comment) and proposed fix 644405b

That sounds ok

Breaking change to be reverted

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

This does not seem to fix the originally described issue, moreover, it looks like this breaks previously working behavior. See #143230 (comment).

Minor detail :D

I think fixed correctly now (based on what you posted) but I need to verify the correct thing happens on arm64e (this will take a few days).

There's still the ifdef'd definition of the helper function in the current version, but I'll move that around in a bit.

@ojhunt ojhunt requested a review from ldionne October 3, 2025 22:27
__ptrauth_unwind_cie_info_personality_disc)

// ptrauth_string_discriminator("personality") == 0x7EAD)
#define __ptrauth_unwind_pacret_personality_disc 0x7EAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the name is a bit misleading. Let's use smth like the following:

Suggested change
#define __ptrauth_unwind_pacret_personality_disc 0x7EAD
#define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD

// __ptrauth_nop_cast cannot be used here as the authentication schemas include
// address diversification.
template <typename PtrType>
void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll open a "placeholder" thread just as a reminder that we need to get #161027 with additional macros merged first, and make use of those macros instead of these functions.

_Unwind_Personality_Fn __ptrauth_unwind_upi_handler *handler;
} u;
u.opaque_handler = (void *)&frameInfo->handler;
return *u.handler;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this should be valid in C, in C++ reading from the member of the union that wasn't most recently written is technically UB: https://en.cppreference.com/w/cpp/language/union.html.

I think we need to conform to C++ standard and use smth like memcpy for doing such a trick.


#include <ptrauth.h>

#if __has_extension(ptrauth_restricted_intptr_qualifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment explaining that we need that because of Apple's fork so people unaware of the problem would know why such checks are needed.

The comment might look like this:

// In Apple's fork of clang, `__ptrauth` qualifier can be only applied to
// pointer types, and `__ptrauth_restricted_intptr` is used instead for
// integer types. In mainline clang, we only have `__ptrauth` which could
// be applied both to pointer and integer types.
// These helper macros allow seemless build of runtime libraries with
// Apple's fork of clang.
// TODO: If/when Apple's clang switches to mainline way of using
// `__ptrauth` qualifier, get rid of these conditionals.

unw_word_t result;
__unw_get_reg(cursor, UNW_REG_IP, &result);

#if defined(__ARM64E__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you've accidentally changes this from a generic check against ptrauth being enabled to a check against arm64e. To make tests passing on Linux, we need to use smth like _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING.

@kovdan01
Copy link
Contributor

kovdan01 commented Oct 6, 2025

@ojhunt Thanks for an update! With the latest fixes, we only have one trivial issue which prevents Linux tests from passing (and I believe that it was introduced accidentally and it looks like that we need literally zero effort to fix that). With that being fixed, tests are passing on Linux in the following configurations:

  1. Pauthtest for both runtime libraries and executables
  2. Pac-ret for both runtime libraries and executables
  3. Pac-ret for executables but not runtime libraries
  4. No pauth at all (on aarch64)

Besides that, there are several other small issues here and there. See the list below.

Please let me know if any help with fixing these issues is needed - I would be glad to provide any support.

  1. Use a check against _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING against a check against arm64e: [runtimes][PAC] Harden unwinding when possible #143230 (comment)
    This is the only thing which prevents linux tests from passing.

  2. Avoid UB in get_handler_function: [runtimes][PAC] Harden unwinding when possible #143230 (comment)
    Similar issue should also be addressed in [clang][PAC][NFC] Provide addition support macros to ptrauth.h #161027 (comment)

(The issues below could be resolved in follow-up PRs, keeping description here not to lose them)

  1. It looks like that while _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING macro was added (and it's used in some places), in most cases we still have plain checks against __has_feature(ptrauth_calls) and __has_feature(ptrauth_returns). As discussed earlier, it's better to use this macro for such checks. See thread [runtimes][PAC] Harden unwinding when possible #143230 (comment) and proposed fix 644405b

  2. Add a comment explaining conditionals regarding __ptrauth_restricted_intptr qualifier to make it clearer for thouse not familiar with Apple's clang specific. I've provided an example comments, see [runtimes][PAC] Harden unwinding when possible #143230 (comment)

  3. __ptrauth_unwind_pacret_personality_disc should probably be renamed to __ptrauth_unwind_pauthtest_personality_disc. It's clearly not related to pac-ret which is about LR signing only. See [runtimes][PAC] Harden unwinding when possible #143230 (comment)

Looking forward for further updates and hope that this could be finally merged relatively soon :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-rt:builtins compiler-rt hardening Issues related to the hardening effort libc++abi libc++abi C++ Runtime Library. Not libc++. libunwind PGO Profile Guided Optimizations
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

6 participants